package etxt2db.features;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import edu.cmu.minorthird.classify.Feature;
import edu.cmu.minorthird.classify.Instance;
import edu.cmu.minorthird.classify.MutableInstance;
import edu.cmu.minorthird.text.AnnotatorLoader;
import edu.cmu.minorthird.text.EmptyLabels;
import edu.cmu.minorthird.text.MutableTextLabels;
import edu.cmu.minorthird.text.Span;
import edu.cmu.minorthird.text.TextBaseLoader;
import edu.cmu.minorthird.text.TextLabels;
import edu.cmu.minorthird.text.Token;
import edu.cmu.minorthird.text.learn.MixupCompatible;
import edu.cmu.minorthird.text.learn.SpanFeatureExtractor;


public class EditableTokenFE implements SpanFeatureExtractor, MixupCompatible, Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 4289599120993315687L;
	transient protected MutableInstance instance;
	@SuppressWarnings("unused")
	transient private TextLabels textLabels=new EmptyLabels();
	protected AnnotatorLoader annotatorLoader=null;
	protected String requiredAnnotation=null;
	protected String requiredAnnotationFileToLoad=null;
	protected int neighborhood;
	
	List<CharacterFeatureClassifier> featuresClassifiers;
	
	public EditableTokenFE(List<CharacterFeatureClassifier> features) throws IOException{
		this(features,3);
	}
	
	public EditableTokenFE(List<CharacterFeatureClassifier> features,int neighborhood) throws IOException{
		featuresClassifiers = features;
		this.neighborhood = neighborhood;
	}
	
	public void parseFeatures(List<String> features) throws IOException{
		FeatureParser parser = new FeatureParser();
		featuresClassifiers = parser.parseFeatures(features);
	}

	public Instance extractInstance(TextLabels labels,Span span) {
		instance=new MutableInstance(span,span.getDocumentGroupId());
		textLabels=labels;
		extractFeatures(labels,span);
		return instance;
	}
	
	public void extractFeatures(TextLabels labels,Span span){
		requireMyAnnotation(labels);
		
		//List<String> strings = getBagOfStrings(span);
		//System.out.println(strings.size());
		//for(int i=0;i<strings.size();i++){
		String str = span.asString();
		for(CharacterFeatureClassifier cfc : featuresClassifiers){
			//System.out.print(cfc.emit(str) + " ");
			cfc.setSpan(span);
			cfc.setTextLabels(labels);
			List<String> feature = cfc.emit(str);
			for(String f : feature){
				emit(f);
			}
		}
		List<String> leftStrings = extractLeftFeatures(span);
		int i = -leftStrings.size();
		for(String leftSpan : leftStrings){
			for(CharacterFeatureClassifier cfc : featuresClassifiers){
				List<String> feature = cfc.emit(leftSpan);
				for(String f : feature){
					emit(i + "_" + f);
				}
			}
			i++;
		}
		i=1;
		for(String rightSpan : extractRightFeatures(span)){
			for(CharacterFeatureClassifier cfc : featuresClassifiers){
				List<String> feature = cfc.emit(rightSpan);
				for(String f : feature){
					emit(i + "_" + f);
				}
			}
			i++;
		}
		//System.out.println("");
	}
	
	private List<String> extractLeftFeatures(Span text){
		int size;
		if(text.documentSpanStartIndex()-neighborhood<0){
			size = text.documentSpanStartIndex();
		}else{
			size = neighborhood;
		}
		return getBagOfStrings(text.documentSpan().subSpan(Math.max(0,text.documentSpanStartIndex()-neighborhood),size));
	}
	
	private List<String> extractRightFeatures(Span text){
		int size;
		if(text.documentSpanStartIndex()+text.size()+neighborhood>text.documentSpan().size()){
			size = text.documentSpan().size()-(text.documentSpanStartIndex()+text.size());
		}else{
			size = neighborhood;
		}
		return getBagOfStrings(text.documentSpan().subSpan(text.documentSpanStartIndex()+text.size(),size));
	}
	
	public void emit(String result){
		//System.out.print(result + " ");
		Feature f=new Feature(result);
		instance.addBinary(f);
	}

	public String getRequiredAnnotation() {
		return requiredAnnotation==null?"":requiredAnnotation;
	}
	

	public void setAnnotatorLoader(AnnotatorLoader newLoader) {
		this.annotatorLoader=newLoader;
	}

	public void setRequiredAnnotation(String requiredAnnotation) {
		this.requiredAnnotation=requiredAnnotation;
	}
	
	private List<String> getBagOfStrings(Span text) {
		List<String> strings = new ArrayList<String>();
		
		SortedSet<Token> set=new TreeSet<Token>();
		for(int i=0;i<text.size();i++){
			set.add(text.getToken(i));
		}
		for(Iterator<Token> i=set.iterator();i.hasNext();){
			Token token=i.next();
			strings.add(token.getValue());
		}
		
		return strings;
	}
	
	public void setRequiredAnnotation(String requiredAnnotation,
			String annotationProvider){
		setRequiredAnnotation(requiredAnnotation);
		setAnnotationProvider(annotationProvider);
	}

	//
	// simpler getter-setter interface, e.g. for GUI configuration
	//

	

	/**
	 * Specify a mixup file or java class to use to provide the annotation.
	 */
	public void setAnnotationProvider(String classNameOrMixupFileName){
		this.requiredAnnotationFileToLoad=classNameOrMixupFileName;
	}

	public String getAnnotationProvider(){
		return requiredAnnotationFileToLoad==null?"":requiredAnnotationFileToLoad;
	}


	/** Make sure the required annotation is present. */
	public void requireMyAnnotation(TextLabels labels){
		labels.require(requiredAnnotation,requiredAnnotationFileToLoad,
				annotatorLoader);
	}
	
	public static void main(String[] args) throws IOException, ParseException{
		File teste = new File("./resources/test/cmu.andrew.official.cmu-news-2457-0");
		TextBaseLoader loaderTest = new TextBaseLoader();
		loaderTest.load(teste);
		MutableTextLabels testeLabels = loaderTest.getLabels();
		List<CharacterFeatureClassifier> features = new ArrayList<CharacterFeatureClassifier>();
		features.add(new ValueCaseSensitiveFeatureClassifier());
		features.add(new ValueCaseInsensitiveFeatureClassifier());
		features.add(new RegexFeatureClassifier("[A-Z][a-z]*"));
		features.add(new DictionaryFeatureClassifier("./resources/names/male.txt"));
		features.add(new SubstringFeatureClassifier(0,3));
		features.add(new SubstringFeatureClassifier(-3,0));
		features.add(new SizeFeatureClassifier());
		features.add(new PatternFeatureClassifier());
		features.add(new CharacterTypeFeatureClassifier());
		
		EditableTokenFE tokenFE = new EditableTokenFE(features);
		Iterator<Span> iter = testeLabels.getTextBase().documentSpanIterator();
		while(iter.hasNext()){
			Span text = iter.next();
			tokenFE.extractInstance(testeLabels, text);
		}
	}
}
